#include <stdio.h>
#include "ts_sec.h"
#include "ts_list.h"
#include "des_list.h"
#include "crc.h"

int TSSEC_make_table_pat(TSELEM *ts_elem, uint8_t *sec_buf_all, uint16_t sec_len_max, uint16_t sec_cnt_max) {
	int i, data;

	uint8_t *sec_buf;
	int sec_pos;

	int sec_cnt, prg_num, pmt_pid, sec_all_len, net_info_tab = 1;

	PRGELEM *prg_elem;

	if(!ts_elem || !ts_elem->prg_list.size || !sec_buf_all || (sec_len_max  < 100))	return 0;

	list_for_each_entry_start(prg_elem, &ts_elem->prg_list.node, node, PRGELEM);

	for(sec_cnt = 0; sec_cnt < sec_cnt_max; ) {
		sec_pos = 0;
		sec_buf = sec_buf_all + sec_len_max * sec_cnt;

		// 8b-table_id
		sec_buf[sec_pos++] = 0x00;

		// 1b-1, 1b-0, 2b-3, 12b-section_length-后面补写
		data = (1 << 15) | (0 << 14) | (3 << 12) | 0;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 16b-ts_id
		data = ts_elem->ts_id & 0xFFFF;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 2b-3, 5b-ver_num, 1b-cur_next_indi
		sec_buf[sec_pos++] = (3 << 6) | ((ts_elem->ver_num & 0x1F) << 1) | 1;

		// 8b-section_number
		sec_buf[sec_pos++] = sec_cnt;

		// 8b-last_setion_number-后面补写
		sec_buf[sec_pos++] = 0;

		// (prg_num, pmt_pid) == (0, 16)  对应  NIT网络信息表 
		if (net_info_tab) {
			net_info_tab = 0;

			// 16b-prg_num
			prg_num = 0x00 & 0xFFFF;
			data = prg_num;
			sec_buf[sec_pos++] = (data >> 8);
			sec_buf[sec_pos++] = (data >> 0);

			// 3b-reserved, 13b-pid
			pmt_pid = 0x10 & 0x1FFF;
			data = (7 << 13) | pmt_pid;
			sec_buf[sec_pos++] = (data >> 8);
			sec_buf[sec_pos++] = (data >> 0);
		}

		for( ; list_for_each_entry_end (prg_elem, &ts_elem->prg_list.node, node, PRGELEM);
			   list_for_each_entry_next(prg_elem, &ts_elem->prg_list.node, node, PRGELEM)) {
			if((sec_pos + 4 + 4) > sec_len_max)	break;

			// 16b-prg_num
			prg_num = prg_elem->prg_num & 0xFFFF;
			data = prg_num;
			sec_buf[sec_pos++] = (data >> 8);
			sec_buf[sec_pos++] = (data >> 0);

			// 3b-reserved, 13b-pid
			pmt_pid = prg_elem->pmt_pid & 0x1FFF;
			data = (7 << 13) | pmt_pid;
			sec_buf[sec_pos++] = (data >> 8);
			sec_buf[sec_pos++] = (data >> 0);
		}

		// 32b-CRC-后面补写
		sec_pos += 4;

		// 补写 section_length
		data = sec_pos - 3;
		sec_buf[1] &= 0xF0;
		sec_buf[1] |= (data >> 8);
		sec_buf[2]  = (data >> 0);

		sec_cnt++;

		// 查看是否结束
		if (!list_for_each_entry_end(prg_elem, &ts_elem->prg_list.node, node, PRGELEM))	break;
	}

	// 重新补写信息
	for(i = 0; i < sec_cnt; i++) {
		sec_buf = sec_buf_all + sec_len_max * i;
		// 补写 8b-last_section_number
		sec_buf[7] = sec_cnt - 1;
		// 补写 32b-CRC
		sec_all_len = os_get_all_sec_len(sec_buf);// 要加前面3字节
		data = crc_get_crc32(sec_buf, sec_all_len - 4);
		sec_buf[sec_all_len - 4 + 0] = (data >> 24);
		sec_buf[sec_all_len - 4 + 1] = (data >> 16);
		sec_buf[sec_all_len - 4 + 2] = (data >>  8);
		sec_buf[sec_all_len - 4 + 3] = (data >>  0);
	}
	
	return sec_cnt;
}

int TSSEC_make_table_pmt(PRGELEM *prg_elem, uint8_t *sec_buf_all, uint16_t sec_len_max, uint16_t sec_cnt_max, int ver_num) {
	int i, data, des_size, err_flag;

	uint8_t *sec_buf;
	int sec_all_len, sec_cnt, sec_pos, sec_pos_tmp;

	ESELEM *es_elem;

	if(!prg_elem || !sec_buf_all || !sec_cnt_max || (sec_len_max < 100)) return 0;

	for(sec_cnt = 0; sec_cnt < sec_cnt_max; ) {
		sec_pos = 0;
		sec_buf = sec_buf_all + sec_len_max * sec_cnt;

		// 8b-table_id
		sec_buf[sec_pos++] = 0x02;

		// 1b-1, 1b-0, 2b-reserved, 12b-section_length-后面补写
		data = (1 << 15) | (0 << 14) | (3 << 12) | 0;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 16b-prg_num
		data = prg_elem->prg_num & 0xFFFF;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 2b-reserved, 5b-ver_num, 1b-curr_next_indi
		sec_buf[sec_pos++] = (3 << 6) | ((ver_num & 0x1F) << 1) | 1;

		// 8b-section_number
		sec_buf[sec_pos++] = sec_cnt;

		// 8b-last_section_number-后面补写
		sec_buf[sec_pos++] = 0;

		// 3b-reserved, 13b-pcr_pid
		data = (0x7 << 13) | (prg_elem->pcr_pid & 0x1FFF);
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 4b-reserved, 12b-prg_info_len-后面补写
		data = (0xF << 12) | 0x0;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);
		sec_pos_tmp = sec_pos; // pos_prg_info_len

		// 描述符
		des_size = DESELEM_LIST_get_buf(&prg_elem->pmt_des_list, sec_buf + sec_pos, sec_len_max - sec_pos - 4, &err_flag);
		sec_pos += des_size;
		// 补写描述符的长度
		data = sec_pos - sec_pos_tmp;
		sec_buf[sec_pos_tmp - 2 + 0] &= 0xF0;
		sec_buf[sec_pos_tmp - 2 + 0] |= (data >> 8);
		sec_buf[sec_pos_tmp - 2 + 1]  = (data >> 0);

		list_for_each_entry(es_elem, &prg_elem->es_list.node, node, ESELEM) {
			if((sec_pos + 5 + 4) > sec_len_max)	break;

			// 8b-stream_type
			sec_buf[sec_pos++] = es_elem->es_type;

			// 3b-reserved, 13b-elementary_pid
			data = (0x7 << 13) | (es_elem->es_pid & 0x1FFF);
			sec_buf[sec_pos++] = (data >> 8);
			sec_buf[sec_pos++] = (data >> 0);

			// 4b-reserved, 12b-es_info_length-后面补写
			data = (0xF << 12) | 0x0;
			sec_buf[sec_pos++] = (data >> 8);
			sec_buf[sec_pos++] = (data >> 0);
			sec_pos_tmp = sec_pos; // pos_es_info_len

			// 描述符
			des_size = DESELEM_LIST_get_buf(&es_elem->des_list, sec_buf + sec_pos, sec_len_max - sec_pos - 4, &err_flag);
			sec_pos += des_size;
			// 补写描述符的长度
			data = sec_pos - sec_pos_tmp;
			sec_buf[sec_pos_tmp - 2 + 0] &= 0xf0;
			sec_buf[sec_pos_tmp - 2 + 0] |= (data >> 8);
			sec_buf[sec_pos_tmp - 2 + 1]  = (data >> 0);
		}

		// 32b-CRC-后面补写
		sec_pos += 4;

		// 补写段长度.
		data = sec_pos - 3;
		sec_buf[1] &= 0xF0;
		sec_buf[1] |= (data >> 8);
		sec_buf[2]  = (data >> 0);

		sec_cnt++;

		// PMT只有1个段,如果要支持多个段, es_list遍历的初始化等等,需重写.
		break;
	}

	// 重新补写信息
	for(i = 0; i < sec_cnt; i++) {
		sec_buf = sec_buf_all + sec_len_max * i;
		// 补写 8b-last_section_number
		sec_buf[7] = sec_cnt - 1;
		// 补写 32b-CRC
		sec_all_len = os_get_all_sec_len(sec_buf);// 要加前面3字节
		data = crc_get_crc32(sec_buf, sec_all_len - 4);
		sec_buf[sec_all_len - 4 + 0] = (data >> 24);
		sec_buf[sec_all_len - 4 + 1] = (data >> 16);
		sec_buf[sec_all_len - 4 + 2] = (data >>  8);
		sec_buf[sec_all_len - 4 + 3] = (data >>  0);
	}
	
	return sec_cnt;
}

int TSSEC_make_table_sdt(TSELEM *ts_elem, uint8_t *sec_buf_all, int sec_len_max, int sec_cnt_max) {
	int i, data;

	uint8_t *sec_buf;
	int sec_pos, sec_pos_tmp;

	int sec_cnt, sec_all_len, pos_des_loop_len;

	PRGELEM *prg_elem;
	uint8_t des_buf[DES_BUF_MAX_LEN];

	int des_loop_all_len;
	int err_flag;

	if(!ts_elem || !sec_buf_all || !sec_cnt_max || (sec_len_max < 100)) return 0;

	list_for_each_entry_start(prg_elem, &ts_elem->prg_list.node, node, PRGELEM);

	for(sec_cnt = 0; sec_cnt < sec_cnt_max; ) {
		sec_pos = 0;
		sec_buf = sec_buf_all + sec_len_max * sec_cnt;

		// 8b-table_id
		sec_buf[sec_pos++] = 0x42;

		// 1b-1, 1b-reserved, 2b-reserved, 12b-seciton_length-后面补写
		data = (1 << 15) | (1 << 14) | (3 << 12) | 0;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 16b-ts_id
		data = ts_elem->ts_id & 0xFFFF;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 2b-reserved, 5b-ver_num, 1b-curr_next_indi
		sec_buf[sec_pos++] = (3 << 6) | ((ts_elem->ver_num & 0x1F) << 1) | 1;

		// 8b-section_number
		sec_buf[sec_pos++] = sec_cnt;

		// 8b-last_section_number-后面补写
		sec_buf[sec_pos++] = 0;

		// 16b-original_network_id
		data = ts_elem->ori_net_id & 0xFFFF;
		sec_buf[sec_pos++] = (data >> 8);
		sec_buf[sec_pos++] = (data >> 0);

		// 8b-reserved_future_use
		sec_buf[sec_pos++] = 0xFF;

		for(                                                                          ;
			list_for_each_entry_end( prg_elem, &ts_elem->prg_list.node, node, PRGELEM);
			list_for_each_entry_next(prg_elem, &ts_elem->prg_list.node, node, PRGELEM), sec_pos = sec_pos_tmp) {
			sec_pos_tmp = sec_pos;
			if((sec_pos_tmp + 5 + 4) > sec_len_max) break;

			// 16b-service_id
			data = prg_elem->prg_num;
			sec_buf[sec_pos_tmp++] = (data >> 8);
			sec_buf[sec_pos_tmp++] = (data >> 0);

			// 24b:	6b-reserved, 1b-eit_sch, 1b-eit_pf, 3b-runing_status, 1b-free_ca_mod, 12b-des_loop_len-后面补写
			data = (0x3F << 18) | (0x0 << 17) | (0x0 << 16) | (0x7 << 13) | (0x0 << 12) | 0;
			sec_buf[sec_pos_tmp++] = (data >> 16);
			sec_buf[sec_pos_tmp++] = (data >>  8);
			sec_buf[sec_pos_tmp++] = (data >>  0);
			pos_des_loop_len = sec_pos_tmp;

			// 节目名称
			des_loop_all_len = DESELEM_buf_set_service(des_buf, prg_elem);
			if((sec_pos_tmp + des_loop_all_len + 4) > sec_len_max) break;
			memcpy(sec_buf + sec_pos_tmp, des_buf, des_loop_all_len);
			sec_pos_tmp += des_loop_all_len;

			// 其他描述符
			des_loop_all_len = DESELEM_LIST_get_buf(&prg_elem->sdt_des_list, sec_buf + sec_pos_tmp, sec_len_max - sec_pos_tmp - 4, &err_flag);
			sec_pos_tmp += des_loop_all_len;
			
			// 补写描述符长度
			data = sec_pos_tmp - pos_des_loop_len;
			sec_buf[pos_des_loop_len - 2 + 0] &= 0xF0;
			sec_buf[pos_des_loop_len - 2 + 0] |= (data >> 8);
			sec_buf[pos_des_loop_len - 2 + 1]  = (data >> 0);

			// 空间不够用
			if(err_flag) break;
		}

		// 32b-CRC-后面补写
		sec_pos += 4;

		// 补写 12b-seciton_length
		data = sec_pos - 3;
		sec_buf[1] &= 0xF0;
		sec_buf[1] |= (data >> 8);
		sec_buf[2]  = (data >> 0);

		sec_cnt++;

		// 查看是否结束
		if(!list_for_each_entry_end( prg_elem, &ts_elem->prg_list.node, node, PRGELEM)) break;
	}
	
	// 重新补写信息
	for(i = 0; i < sec_cnt; i++) {
		sec_buf = sec_buf_all + sec_len_max * i;
		// 补写 8b-last_section_number
		sec_buf[7] = sec_cnt - 1;
		// 补写 32b-CRC
		sec_all_len = os_get_all_sec_len(sec_buf);
		data = crc_get_crc32(sec_buf, sec_all_len - 4);
		sec_buf[sec_all_len - 4 + 0] = (data >> 24);
		sec_buf[sec_all_len - 4 + 1] = (data >> 16);
		sec_buf[sec_all_len - 4 + 2] = (data >>  8);
		sec_buf[sec_all_len - 4 + 3] = (data >>  0);
	}

	return sec_cnt;
}

static inline void __insert_sec_2_pkt_list__(LIST *pkt_list, uint8_t *sec_buf_all, uint16_t sec_len_max, uint16_t sec_cnt, int pid) {
	uint16_t sec_idx;
	uint8_t *sec_buf;

 	if (!pkt_list || !sec_buf_all) return;

	for(sec_idx = 0; sec_idx < sec_cnt; sec_idx++) {
		sec_buf = sec_buf_all + sec_len_max * sec_idx;
		PKTELEM_LIST_insert_sec(pkt_list, sec_buf, pid);
	}
}

void TSSEC_make_table(LIST *ts_list) {
	uint16_t sec_cnt;
	const uint16_t sec_len_max = (3 + 1021), sec_cnt_max = (0xFF + 1);
	uint8_t *sec_buf_all;

	TSELEM  *ts_elem;
	PRGELEM *prg_elem;

	if(!ts_list) return;

	sec_buf_all = os_calloc(sec_len_max * sec_cnt_max);
	if(!sec_buf_all) return;

	list_for_each_entry(ts_elem, &ts_list->node, node, TSELEM) {
		// PAT
		sec_cnt = TSSEC_make_table_pat(ts_elem, sec_buf_all, sec_len_max, sec_cnt_max);
		__insert_sec_2_pkt_list__(&ts_elem->pat_pkt_list, sec_buf_all, sec_len_max, sec_cnt, 0x0000);

		// PMT
		list_for_each_entry(prg_elem, &ts_elem->prg_list.node, node, PRGELEM) {
			sec_cnt = TSSEC_make_table_pmt(prg_elem, sec_buf_all, sec_len_max, sec_cnt_max, ts_elem->ver_num);
			__insert_sec_2_pkt_list__(&ts_elem->pmt_pkt_list, sec_buf_all, sec_len_max, sec_cnt, prg_elem->pmt_pid);
		}

		// SDT
		sec_cnt = TSSEC_make_table_sdt(ts_elem, sec_buf_all, sec_len_max, sec_cnt_max);
		__insert_sec_2_pkt_list__(&ts_elem->sdt_pkt_list, sec_buf_all, sec_len_max, sec_cnt, 0x0011);
	}

	os_free(sec_buf_all);

	return;
}
